
//
// 121002 - AH - Created.
// 121226 - AH - save(File, String).
// 130324 - AH - getNewFile(File, String, String).
// 130603 - AH - read(InputStream).
//

package org.japril.jutil;

import java.io.BufferedReader;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Random;

/**
 * <p>
 *   Utility methods of use when working with java i/o.
 * </p>
 * @author Arne Halvorsen (AH)
 */
public final class IOUtil 
{
  private IOUtil(){} // Utility pattern dictates private constructor.
  
  /**
   * <p>
   *   Writes to a text file.
   * </p>
   * @param f   {@link File} to write to.
   * @param txt Text to write, if {@code null} writes 'null'.
   * @throws IOException If fails.
   */
  public static void save(File f, String txt) throws IOException
  {
    if (f==null)
    {
      throw new NullPointerException("f");
    }
    
    txt=(txt==null) ? "null" : txt;
    
    Writer w=null;
    try
    {
      w=new FileWriter(f);
      w.write(txt);
    }
    finally
    {
      if (w!=null) try { w.close(); } catch (IOException _){}
    }
  }
  
  /**
   * <p>
   *   Reads a text file.
   * </p>
   * @param f {@link File} to read.
   * @return Text read.
   * @throws IOException If fails.
   */
  public static String read(File f) throws IOException
  {
    if (f==null)
    {
      throw new NullPointerException("f");
    }
    
    FileReader fr=new FileReader(f);
    BufferedReader br=new BufferedReader(fr);
    return read(br);
  }
  
  /**
   * <p>
   *   Reads text.
   * </p>
   * @param br Stream to read.
   * @return Text read.
   * @throws IOException If fails.
   */
  public static String read(InputStream is) throws IOException
  {
    if (is==null)
    {
      throw new NullPointerException("is");
    }
    
    BufferedReader br=new BufferedReader(new InputStreamReader(is));
    return read(br);
  }
  
  /**
   * <p>
   *   Reads text.
   * </p>
   * @param br Stream to read.
   * @return Text read.
   * @throws IOException If fails.
   */
  public static String read(BufferedReader br) throws IOException
  {
    CharArrayWriter caw=new CharArrayWriter();
    PrintWriter pw=new PrintWriter(caw);
    
    String line=br.readLine();
    while (line!=null)
    {
      pw.println(line);
      line=br.readLine();
    }
    
    pw.flush();
    return caw.toString();
  }
  
  /**
   * <p>
   *   Creates an empty file in a directory with an unique name among files in
   *   the directory.
   * </p>
   * <p>
   *   Alternative to 
   *   {@link File#createTempFile(String, String, File)} that may be slow but
   *   probably is guaranteed to manage to create unique file name.
   * </p>
   * @param dir  Directory, if {@code null} created in current working
   *             directory.
   * @param pfix Optional (may be {@code null}) suffix.
   * @param sfix Optional (may be {@code null}) file extension. If given may
   *             contain '.' but is not required to have.
   * @return {@link File} representing created file. There is a chance
   *         (probably very very slim) this fails creating a unique file name,
   *         but if so, returns {@code null}.
   * @throws IOException If fails.
   */
  public static synchronized File getNewFile(File dir, String pfix, 
    String sfix) throws IOException
  {
    if (dir==null)
    {
      throw new NullPointerException("dir");
    }
    
    dir=(dir==null) ? new File("./") : dir;
    
    if (!dir.isDirectory())
    {
      throw new IllegalArgumentException("not a directory: "+dir);
    }
    
    pfix=(pfix==null) ? "" : pfix.trim();
    
    sfix=(sfix==null) ? "" : sfix.trim();
    sfix=(sfix.length()==0) ? null : sfix;
    
    StringBuilder sb=new StringBuilder();
    
    File retVal=null;
    
    Random rnd=new Random();
    boolean created=false;
    for (int i=0; i<100 && !created; i++)
    {
      sb.setLength(0);
      int k=rnd.nextInt();
      sb.append(pfix).append('_').append(k);
      if (sfix!=null)
      {
        if (sfix.charAt(0)!='.') sb.append('.');
        sb.append(sfix);
        retVal=new File(dir, sb.toString());
        if (!retVal.exists()) 
        {
          if (retVal.createNewFile()) created=true;
        }
      }
    }
    
    return created ? retVal : null;
  }
  
}
